package cn.stylefeng.guns.modular.gridsystem.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.guns.core.exception.ServiceException;
import cn.stylefeng.guns.core.factory.PageFactory;
import cn.stylefeng.guns.core.pojo.page.PageResult;
import cn.stylefeng.guns.modular.gridsystem.constants.GatewayTaskStatusConstant;
import cn.stylefeng.guns.modular.gridsystem.constants.GatewayTaskTypeConstant;
import cn.stylefeng.guns.modular.gridsystem.entity.BizGateway;
import cn.stylefeng.guns.modular.gridsystem.entity.GatewayTask;
import cn.stylefeng.guns.modular.gridsystem.entity.GatewayTaskRecord;
import cn.stylefeng.guns.modular.gridsystem.enums.GatewayExceptionEnum;
import cn.stylefeng.guns.modular.gridsystem.enums.GatewayTaskExceptionEnum;
import cn.stylefeng.guns.modular.gridsystem.mapper.BizGatewayMapper;
import cn.stylefeng.guns.modular.gridsystem.mapper.GatewayTaskMapper;
import cn.stylefeng.guns.modular.gridsystem.mapper.GatewayTaskRecordMapper;
import cn.stylefeng.guns.modular.gridsystem.model.param.GatewayTaskParam;
import cn.stylefeng.guns.modular.gridsystem.model.result.GatewayTaskResult;
import cn.stylefeng.guns.modular.gridsystem.service.GatewayTaskService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * 网关任务下发表 服务实现类
 *
 * @author zxw
 * @date 2022/10/31 14:34
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class GatewayTaskServiceImpl extends ServiceImpl<GatewayTaskMapper, GatewayTask> implements GatewayTaskService {

    private final GatewayTaskRecordMapper recordMapper;

    private final BizGatewayMapper gatewayMapper;

    @Override
    public PageResult<GatewayTaskResult> page(GatewayTaskParam param) {
        return new PageResult<>(this.baseMapper.pagelist(PageFactory.defaultPage(), param));
    }

    @Override
    public PageResult<GatewayTaskResult> pageTaskList(GatewayTaskParam param) {
        return new PageResult<>(this.baseMapper.pageTaskList(PageFactory.defaultPage(), param));
    }

    @Override
    public List<GatewayTask> list(GatewayTaskParam gatewayTaskParam) {

        // 构造条件
        LambdaQueryWrapper<GatewayTask> queryWrapper = new LambdaQueryWrapper<>();

        return this.list(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(GatewayTaskParam param) {

        GatewayTask task = BeanUtil.toBean(param, GatewayTask.class);
        task.setTaskStatus(GatewayTaskStatusConstant.WAIT_ISSUED);
        // 保存任务信息
        this.save(task);

        // 保存任务对应的网关信息
        for (Integer gatewayId : param.getGatewayIds()) {
            GatewayTaskRecord record = GatewayTaskRecord.builder()
                    .taskId(task.getId())
                    .gatewayId(gatewayId)
                    .taskStatus(GatewayTaskStatusConstant.WAIT_ISSUED)
                    .build();
            recordMapper.insert(record);
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long add(String taskType, List<Integer> gatewayIds, String taskParam) {

        GatewayTask task = GatewayTask.builder()
                .taskType(taskType)
                .taskStatus(GatewayTaskStatusConstant.ISSUED)
                .issuedTime(DateTime.now())
                .build();
        if (ObjectUtil.isNotEmpty(taskParam)) {
            task.setTaskParams(taskParam);
        }
        this.save(task);

        if (ObjectUtil.isEmpty(gatewayIds) || gatewayIds.size() == 0) {
            log.warn("关联网关不能为空");
            throw new ServiceException(GatewayTaskExceptionEnum.GATEWAY_IDS_NOT_ALLOWED_EMPTY);
        }
        // 保存任务对应的网关信息
        for (Integer gatewayId : gatewayIds) {
            GatewayTaskRecord record = GatewayTaskRecord.builder()
                    .taskId(task.getId())
                    .gatewayId(gatewayId)
                    .taskStatus(GatewayTaskStatusConstant.ISSUED)
                    .build();
            recordMapper.insert(record);
        }

        return ObjectUtil.isEmpty(task.getId()) ? 0 : task.getId();

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(GatewayTaskParam gatewayTaskParam) {
        // 根据id查询实体
        GatewayTask gatewayTask = this.queryGatewayTask(gatewayTaskParam);

        /*if (!GatewayTaskStatusConstant.WAIT_ISSUED.equals(gatewayTask.getTaskStatus())) {
            log.warn("只有待下发的任务才可以删除,任务主键为：{}", gatewayTaskParam.getId());
            throw new ServiceException(GatewayTaskExceptionEnum.WAIT_ISSUED_CAN_DELETE);
        }*/

        // 删除子表信息
        recordMapper.delete(new LambdaUpdateWrapper<GatewayTaskRecord>().eq(GatewayTaskRecord::getTaskId, gatewayTask.getId()));

        this.removeById(gatewayTaskParam.getId());
    }

    @Override
    public void edit(GatewayTaskParam param) {

        // 根据id查询实体
        GatewayTask gatewayTask = this.queryGatewayTask(param);

        // 删除子表信息
        recordMapper.delete(new LambdaUpdateWrapper<GatewayTaskRecord>().eq(GatewayTaskRecord::getTaskId, gatewayTask.getId()));

        if (!GatewayTaskStatusConstant.WAIT_ISSUED.equals(gatewayTask.getTaskStatus())) {
            log.warn("只有待下发的任务才可以编辑,任务主键为：{}", param.getId());
            throw new ServiceException(GatewayTaskExceptionEnum.WAIT_ISSUED_CAN_EDIT);
        }

        // 请求参数转化为实体
        BeanUtil.copyProperties(param, gatewayTask);
        this.updateById(gatewayTask);

        // 保存子表信息
        for (Integer gatewayId : param.getGatewayIds()) {
            GatewayTaskRecord record = GatewayTaskRecord.builder()
                    .taskId(gatewayTask.getId())
                    .taskStatus(GatewayTaskStatusConstant.WAIT_ISSUED)
                    .gatewayId(gatewayId)
                    .build();
            recordMapper.insert(record);
        }

    }

    @Override
    public void issued(GatewayTaskParam param) {
        // 根据id查询实体
        GatewayTask gatewayTask = this.queryGatewayTask(param);
        if (!GatewayTaskStatusConstant.WAIT_ISSUED.equals(gatewayTask.getTaskStatus())) {
            log.warn("任务状态不是待下发,任务主键为：{}", param.getId());
            throw new ServiceException(GatewayTaskExceptionEnum.TASK_STATUS_NOT_WAIT_ISSUED);
        }

        gatewayTask.setTaskStatus(GatewayTaskStatusConstant.ISSUED);
        gatewayTask.setIssuedTime(new Date());
        this.updateById(gatewayTask);

        // 查询子表数据
        List<GatewayTaskRecord> records = recordMapper.selectList(new LambdaQueryWrapper<GatewayTaskRecord>().eq(GatewayTaskRecord::getTaskId, gatewayTask.getId()));
        if (ObjectUtil.isNotEmpty(records)) {
            for (GatewayTaskRecord record : records) {
                record.setTaskStatus(GatewayTaskStatusConstant.ISSUED);
                recordMapper.updateById(record);
            }
        }
    }

    @Override
    public void rollback(GatewayTaskParam param) {

        // 根据id查询实体
        GatewayTask gatewayTask = this.queryGatewayTask(param);
        if (!GatewayTaskStatusConstant.ISSUED.equals(gatewayTask.getTaskStatus())) {
            log.warn("只能撤回已下发的任务,任务主键为：{}", param.getId());
            throw new ServiceException(GatewayTaskExceptionEnum.ISSUED_TASK_CAN_ROLLBACK);
        }
        // 不能撤回自动下发的任务
        if (GatewayTaskTypeConstant.UPDATE_FIRMWARE.equals(gatewayTask.getTaskType()) || GatewayTaskTypeConstant.UPLOAD_NEW_FILE.equals(gatewayTask.getTaskType())
                || GatewayTaskTypeConstant.REGISTER_MODEL.equals(gatewayTask.getTaskType()) || GatewayTaskTypeConstant.SYNC_MODEL.equals(gatewayTask.getTaskType())) {
            log.warn("不能撤回自动下发的任务,任务主键为：{}", param.getId());
            throw new ServiceException(GatewayTaskExceptionEnum.CANNOT_ROLLBACK_AUTO_TASK);
        }

        // 不能撤回已有子表设备响应的任务
        if (recordMapper.selectCount(new LambdaQueryWrapper<GatewayTaskRecord>().eq(GatewayTaskRecord::getTaskId, gatewayTask.getId())
                .eq(GatewayTaskRecord::getTaskStatus, GatewayTaskStatusConstant.RESPONSE)) > 0) {
            log.warn("不能撤回已有设备响应的任务,任务主键为：{}", param.getId());
            throw new ServiceException(GatewayTaskExceptionEnum.CANNOT_ROLLBACK_RESPONSE_TASK);
        }

        gatewayTask.setTaskStatus(GatewayTaskStatusConstant.WAIT_ISSUED);
        gatewayTask.setIssuedTime(DateTime.now());
        this.updateById(gatewayTask);

        // 查询子表数据
        List<GatewayTaskRecord> records = recordMapper.selectList(new LambdaQueryWrapper<GatewayTaskRecord>().eq(GatewayTaskRecord::getTaskId, gatewayTask.getId()));
        if (ObjectUtil.isNotEmpty(records)) {
            for (GatewayTaskRecord record : records) {
                record.setTaskStatus(GatewayTaskStatusConstant.WAIT_ISSUED);
                recordMapper.updateById(record);
            }
        }
    }

    @Override
    public GatewayTask detail(GatewayTaskParam gatewayTaskParam) {
        return this.queryGatewayTask(gatewayTaskParam);
    }

    /**
     * 获取网关任务下发表
     *
     * @author zxw
     * @since 2022/10/31 14:34
     */
    private GatewayTask queryGatewayTask(GatewayTaskParam gatewayTaskParam) {
        GatewayTask gatewayTask = this.getById(gatewayTaskParam.getId());
        if (ObjectUtil.isEmpty(gatewayTask)) {
            log.warn("下发任务不存在,任务主键为：{}", gatewayTaskParam.getId());
            throw new ServiceException(GatewayTaskExceptionEnum.NOT_EXISTED);
        }
        return gatewayTask;
    }

    /**
     * 查询当天已下发状态的任务
     *
     * @author rdp
     * @date 2022/10/31 16:17
     */
    @Override
    public List<GatewayTask> getTodayGatewayTask(GatewayTaskParam gatewayTaskParam) {
        // 构造条件
        gatewayTaskParam.setTaskStatus(GatewayTaskStatusConstant.ISSUED);
        List<GatewayTask> list = this.baseMapper.getTodayGatewayTask(gatewayTaskParam);
        return list;
    }

    /**
     * 上报任务执行的回执
     *
     * @author rdp
     * @date 2022/10/31 16:17
     */
    @Override
    public void callbackGatewayTask(GatewayTaskParam param) {

        // 根据id查询实体
        GatewayTask gatewayTask = this.getById(param.getId());
        if (ObjectUtil.isEmpty(gatewayTask)) {
            log.warn("下发任务不存在,任务主键为：{}", param.getId());
            throw new ServiceException(GatewayTaskExceptionEnum.NOT_EXISTED);
        }
        if (!ObjectUtil.equals(GatewayTaskStatusConstant.ISSUED, gatewayTask.getTaskStatus())) {
            log.warn("下发任务状态不是已下发,任务主键为：{}", param.getId());
            throw new ServiceException(GatewayTaskExceptionEnum.TASK_STATUS_NOT_ALREADY_ISSUED);
        }

        BizGateway gateway = gatewayMapper.selectOne(new LambdaQueryWrapper<BizGateway>().eq(BizGateway::getGatewayCode, param.getGatewayCode()).last("limit 1"));
        if (ObjectUtil.isEmpty(gateway)) {
            log.warn("设备编号错误,设备编号为：{}", param.getGatewayCode());
            throw new ServiceException(GatewayExceptionEnum.CODE_ERROR);
        }

        // 修改任务状态
        GatewayTaskRecord record = recordMapper.selectOne(new LambdaQueryWrapper<GatewayTaskRecord>().eq(GatewayTaskRecord::getTaskId, gatewayTask.getId())
                .eq(GatewayTaskRecord::getGatewayId, gateway.getId()).last("limit 1"));
        record.setTaskStatus(GatewayTaskStatusConstant.RESPONSE);
        record.setResponseTime(DateTime.now());
        record.setResponseResult(param.getResponseResult());
        recordMapper.updateById(record);

        // 查询所有的关联网关，如果所有关联网关都已响应，则将任务状态修改为已响应
        if (recordMapper.selectCount(new LambdaQueryWrapper<GatewayTaskRecord>()
                .eq(GatewayTaskRecord::getTaskId, gatewayTask.getId())
                .ne(GatewayTaskRecord::getTaskStatus, GatewayTaskStatusConstant.RESPONSE)) == 0) {
            // 修改状态
            gatewayTask.setTaskStatus(GatewayTaskStatusConstant.RESPONSE);
            this.updateById(gatewayTask);
        }

    }
}
